<template>
  <div class="home">
    <div id="tiandi-map" class="map" style="width: 100%; height: 100%"></div>

    <div class="track-control" :class="isDesc?'track-control-20':'track-control-410'">
      <img v-show="isPlay" src="@/assets/images/work/bofang.png" alt="播放" @click="handlePlay">
      <img v-show="!isPlay" src="@/assets/images/work/zanting.png" alt="暂停" @click="handlePlay">
      <img class="ml10" src="@/assets/images/work/tingzhi.png" alt="停止" @click="handlePause">
      <div class="time-text ml10 mr20">{{ formattedTimes[sliding] || '00:00:00' }}</div>  
      <el-slider :disabled="isDisabled" @change="handleSliding" style="width:210px;" v-model="sliding" :min="0" :max="formattedTimes.length>0?formattedTimes.length-1:0" :show-tooltip="false"></el-slider>    
      <div class="time-text ml10">{{ formattedTimes[formattedTimes.length-1] || '00:00:00' }}</div>
      <el-select :disabled="isDisabled" class="ml10" size="small" style="width:160px;" v-model="speed" @change="handleSpeed" placeholder="请选择">
        <el-option
          v-for="item in speedOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value">
        </el-option>
      </el-select>
      <el-checkbox v-if="isDisabled" class="ml20" v-model="location" @change="handleLocation">实时定位</el-checkbox>   
      <div class="desc">
        <img v-show="isDesc" src="@/assets/images/work/desc.png" @click="handleDesc">
        <img v-show="!isDesc" src="@/assets/images/work/desc-active.png" @click="handleDesc">
      </div>     
    </div>

    <div class="track-detail-dom" v-if="!isDesc">
      <el-table v-loading="tableLoading" :data="tablePointList" :height="330">
        <el-table-column label="序号" align="center" type="index" width="100" />
        <el-table-column label="定位时间" align="center" prop="createTime"/>
        <el-table-column label="定位经度" align="center" prop="lng"/>
        <el-table-column label="定位纬度" align="center" prop="lat"/>
      </el-table>
    </div>
  </div>
</template>

<script setup name="Index">
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import 'leaflet.chinatmsproviders';
import 'leaflet-trackline';
import { trackArr } from './track.js';
const { proxy } = getCurrentInstance();
import startIconUrl from '@/assets/images/work/start.png';
import endIconUrl from '@/assets/images/work/end.png';
import markerIconUrl from '@/assets/images/work/jq.png';

let map,TrackLine;
const emits = defineEmits();

const isDisabled = ref(false);
const startTime = ref('00:00:00');
const endTime = ref('00:00:00');
const sliding = ref(0);
const speed = ref(1000);
const point = ref(false);
const location = ref(true);
const isPlay = ref(true);
const isDesc = ref(true);
const formattedTimes = ref([]);
const tableLoading = ref(false);
const tablePointList = ref([]);
let timing = null;
const distance = 10;
const earthRadius = 6371000;

const speedOptions = ref([
  {
    label:'播放速度(16x)',
    value: 64
  },
  {
    label:'播放速度(8x)',
    value: 125
  },
  {
    label:'播放速度(4x)',
    value: 250
  },
  {
    label:'播放速度(2x)',
    value: 500
  },
  {
    label:'播放速度(正常)',
    value: 1000
  }
]);

function initMap() {
  const basemapLayer0 = L.tileLayer.chinaProvider('TianDiTu.Normal.Map');
  const basemapLayer1 = L.tileLayer.chinaProvider('TianDiTu.Normal.Annotion');
  const basemapLayer2 = L.tileLayer.chinaProvider('TianDiTu.Satellite.Map');
  const basemapLayer3 = L.tileLayer.chinaProvider('TianDiTu.Satellite.Annotion');

  const basemap1 = L.layerGroup([basemapLayer0, basemapLayer1]);
  const basemap2 = L.layerGroup([basemapLayer2,basemapLayer3]);
  map = L.map('tiandi-map', {
    preferCanvas: true,
    zoomControl: false,
    zoomAnimation: true,
    layers: [basemap2],
    doubleClickZoom: true,
    attributionControl: false,
    minZoom: 5,
    maxZoom: 18
  }).setView([31.815908, 117.185687], 18);         
}

function getList(){
  tableLoading.value = true;
  formattedTimes.value = splitTimesIntoStopwatchFormat(trackArr); 
  const option = {
    startIconOptions: {iconUrl:startIconUrl,iconSize:[25, 32]},
    endIconOptions: {iconUrl:endIconUrl,iconSize:[25, 32]},
    markerIconOptions: {iconUrl:markerIconUrl,iconSize:[25, 32]},
    weight: 4,
    location: isDisabled.value,
    speed: speed.value,
    notPassedLineOptions: { weight:4, color: "#FB7B01", opacity: 1 },
    passedLineOptions: { weight:4, color: "#0FE217", opacity: 1 }
  }
  tablePointList.value = trackArr;
  TrackLine = new L.TrackLine(trackArr,option).addTo(map);
  if (isDisabled.value) {      
    getRealPoint();       
  }   
  tableLoading.value = false;  
}

function getRealPoint(){
  timing = setInterval(() => {
    const { lng,lat } = trackArr[trackArr.length-1];
    const newPosition = calculateNewPosition(lat, lng, distance, randomInt(0, 90));
    tablePointList.value.push(newPosition);
    formattedTimes.value = splitTimesIntoStopwatchFormat(tablePointList.value);
    sliding.value = formattedTimes.value.length - 1;
    TrackLine.updateTrack(tablePointList.value,location.value)
  }, 1000);
}

function handleLocation(flag){
  location.value = flag;
  if (isDisabled.value && location.value) {
    if (timing) {
      clearInterval(timing);
      timing = null;
    }    
    getRealPoint();
  }
}

function parseTime(time, pattern) {
  if (arguments.length === 0 || !time) {
    return null
  }
  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
      time = parseInt(time)
    } else if (typeof time === 'string') {
      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
    }
    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}

const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

function calculateNewPosition(lat, lon, distance, bearing) {
  const lat1 = (lat * Math.PI) / 180;
  const lon1 = (lon * Math.PI) / 180;
  const brng = (bearing * Math.PI) / 180;
  const d = distance / earthRadius;
  const lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) +
                         Math.cos(lat1) * Math.sin(d) * Math.cos(brng));
  const lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(d) * Math.cos(lat1),
                                 Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));

  return {
    createTime:parseTime(new Date()),
    lat: (lat2 * 180) / Math.PI,
    lng: (lon2 * 180) / Math.PI
  };
}

function convertToStopwatchFormat(ms) {
  const hours = Math.floor(ms / (1000 * 60 * 60));
  const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60));
  const seconds = Math.floor((ms % (1000 * 60)) / 1000);
  return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}

function parseDate(dateStr) {
  return new Date(dateStr.replace(' ', 'T') + 'Z');
}

function splitTimesIntoStopwatchFormat(data) {
  const times = data.map(item => parseDate(item.createTime));      
  const startTime = new Date(Math.min(...times));
  const endTime = new Date(Math.max(...times));      
  const totalDurationMs = endTime - startTime;
  const segmentDurationMs = totalDurationMs / (times.length - 1);
  const formattedTimes = [];
  for (let i = 0; i < times.length; i++) {
    const segmentTimeMs = startTime.getTime() + (segmentDurationMs * i);
    const formattedTime = convertToStopwatchFormat(segmentTimeMs - startTime.getTime());
    formattedTimes.push(formattedTime);
  }
  return formattedTimes;
}

function handlePlay(){      
  if (isDisabled.value) return false;
  if (isPlay.value) {
    TrackLine.start(sliding.value); 
    TrackLine.eventEmitter.addEventListener('progress', eventListener); 
  }else{
    TrackLine.pause();        
  }
  isPlay.value = !isPlay.value;
}

function handlePause(){
  if (isDisabled.value) return false;
  TrackLine.pause();      
  TrackLine.setProgress(0); 
  sliding.value = 0;
  isPlay.value = true;
}

function handleSpeed(){
 TrackLine.setSpeed(sliding.value,speed.value)        
}

function changeSliding(index){  
  sliding.value = index;
  if (index == formattedTimes.value.length-1) {
    isPlay.value = true;
  }
}

function handleSliding(){
  TrackLine.setProgress(sliding.value);     
}

function handleDesc(){
  isDesc.value = !isDesc.value;
}

function eventListener(event){
  changeSliding(event.detail);
}

onMounted(() => {
  initMap();
  getList();  
});

onBeforeUnmount(() => {
  if (timing) {
    clearInterval(timing);
  }
  TrackLine.eventEmitter.removeEventListener('progress', eventListener);
  TrackLine.remove();
});
</script>

<style scoped lang="scss">
.home{
  width: 100vw;
  height: 100vh;
  position: absolute;  
  left: 0;
  top: 0;
}

.track-control{
  position: absolute;
  left: 50%;
  z-index: 999;
  width: 650px;
  height: 50px;        
  transform: translate(-50%);
  background: #fff;
  border-radius: 24px;
  padding: 0 20px;
  font-size: 14px;
  color: #424242;
  display: flex;
  align-items: center;
  justify-content: space-between;
  img{
    cursor: pointer;
  }
  .time-text{
    color: #1eac63;
  }
  .desc{
    position: absolute;
    right: -10px;
    transform: translateX(100%);
  }
  .ml10{
    margin-left: 10px;    
  }
  .mr10{
    margin-right: 10px;    
  }
  .ml20{
    margin-left: 20px;
  }
  .mr20{
    margin-right: 20px;
  }
}

.track-control-20{
  bottom: 20px;
}

.track-control-410{
  bottom: 410px;
}

.track-detail-dom{
  position: absolute;
  left: 50%;
  bottom: 20px;
  transform: translate(-50%);
  z-index: 999;
  width: calc(100% - 100px);
  height: 360px;
  background-color: #fff;
  border-radius: 10px;
  padding: 10px 20px;
}
</style>